from __future__ import division

from cStringIO import StringIO

import numpy as np
import Image

from pydap.responses.lib import BaseResponse
from pydap.model import *
from pydap.lib import walk


WIDTH = HEIGHT = 64 * 4
SIZE = WIDTH, HEIGHT
MARGIN = 0    # distance from cube to border of image
DEPTH = WIDTH//8    # depth of the cube
SIDE = WIDTH - 2*MARGIN - DEPTH
BGCOLOR = 255, 255, 255, 0


class ThumbnailResponse(BaseResponse):

    __description__ = "Thumbnail plot"

    def __init__(self, dataset):
        BaseResponse.__init__(self, dataset)
        self.headers.extend([
                ('Content-description', 'dods_thumbnail'),
                ('Content-type', 'image/png'),
                ])

    def __call__(self, environ, start_response):
        self.serialize = self._get_thumbnail(environ)
        return BaseResponse.__call__(self, environ, start_response)

    def _get_thumbnail(self, environ):
        def serialize(dataset):
            output = StringIO()
            im = Image.new('RGBA', SIZE, BGCOLOR)

            # plot first grid
            for var in walk(dataset, GridType):
                dims = len(var.shape)
                if dims > 2:
                    # calculate optimal steps 
                    stepi = max(1, var.shape[-1] // SIDE)
                    stepj = max(1, var.shape[-2] // SIDE)
                    stepl = max(1, var.shape[0] // DEPTH)

                    # download data for the front of the cube
                    slice_ = (0,)*(dims-2) + (slice(0, None, stepj), slice(0, None, stepi))
                    front = np.squeeze(np.asarray(var.array[slice_]))
                    front = front[::-1]  # flip y axis
                    front = mask_array(front, var.attributes)

                    # download data for the top
                    slice_ = (slice(0, None, stepl),) + (0,)*(dims-3) + (var.shape[-2]-1, slice(0, None, stepi))
                    top = np.squeeze(np.asarray(var.array[slice_]))
                    top = top[::-1]  # flip y axis
                    top = mask_array(top, var.attributes)

                    # download data for the side
                    slice_ = (slice(0, None, stepl),) + (0,)*(dims-3) + (slice(0, None, stepj), var.shape[-1]-1)
                    side = np.squeeze(np.asarray(var.array[slice_]))
                    side = side.T[::-1]  # transpose and flip y axis
                    side = mask_array(side, var.attributes)

                    # get data range
                    min_ = min(map(np.min, [front, top, side]))
                    max_ = max(map(np.max, [front, top, side]))

                    # normalize data for plotting
                    front = normalize(front, min_, max_)
                    top = normalize(top, min_, max_)
                    side = normalize(side, min_, max_)

                    # plot front
                    layer = Image.fromarray(front, 'L')
                    layer.putpalette(jet)
                    layer = layer.resize((SIDE, SIDE))
                    im.paste(layer, (MARGIN, MARGIN+DEPTH))

                    # plot top
                    layer = Image.fromarray(top, 'L')
                    layer.putpalette(jet)
                    layer = layer.resize((SIDE, DEPTH)).convert('RGBA')
                    layer = layer.transform((SIDE+DEPTH, DEPTH), Image.AFFINE, (1,1,-DEPTH,0,1,0))
                    im.paste(layer, (MARGIN, MARGIN), layer)

                    # plot side
                    layer = Image.fromarray(side, 'L')
                    layer.putpalette(jet)
                    layer = layer.resize((DEPTH, SIDE)).convert('RGBA')
                    layer = layer.transform((DEPTH, SIDE+DEPTH), Image.AFFINE, (1,0,0,1,1,-DEPTH))
                    im.paste(layer, (MARGIN+SIDE, MARGIN), layer)

                    break

            im.save(output, 'png')
            if hasattr(dataset, 'close'): dataset.close()
            return [ output.getvalue() ]

        return serialize


def mask_array(array, attributes):
    if 'missing_value' in attributes:
        data = np.ma.masked_values(array, attributes['missing_value'])
    elif '_FillValue' in attributes:
        data = np.ma.masked_values(array, attributes['_FillValue'])
    else:
        data = np.ma.asarray(array)
    return data


def normalize(array, min_, max_):
    array -= min_
    array /= (max_ - min_)
    return (array * 254.).filled(255.).astype('B')


jet = np.array([0.0, 0.0, 127.5, 0.0, 0.0, 132.045454545, 0.0, 0.0, 136.590909091, 0.0, 0.0, 141.136363636, 0.0, 0.0, 145.681818182, 0.0, 0.0, 150.227272727, 0.0, 0.0, 154.772727273, 0.0, 0.0, 159.318181818, 0.0, 0.0, 163.863636364, 0.0, 0.0, 168.409090909, 0.0, 0.0, 172.954545455, 0.0, 0.0, 177.5, 0.0, 0.0, 182.045454545, 0.0, 0.0, 186.590909091, 0.0, 0.0, 191.136363636, 0.0, 0.0, 195.681818182, 0.0, 0.0, 200.227272727, 0.0, 0.0, 204.772727273, 0.0, 0.0, 209.318181818, 0.0, 0.0, 213.863636364, 0.0, 0.0, 218.409090909, 0.0, 0.0, 222.954545455, 0.0, 0.0, 227.5, 0.0, 0.0, 232.045454545, 0.0, 0.0, 236.590909091, 0.0, 0.0, 241.136363636, 0.0, 0.0, 245.681818182, 0.0, 0.0, 250.227272727, 0.0, 0.0, 254.772727273, 0.0, 0.0, 255.0, 0.0, 0.0, 255.0, 0.0, 0.0, 255.0, 0.0, 0.5, 255.0, 0.0, 4.5, 255.0, 0.0, 8.5, 255.0, 0.0, 12.5, 255.0, 0.0, 16.5, 255.0, 0.0, 20.5, 255.0, 0.0, 24.5, 255.0, 0.0, 28.5, 255.0, 0.0, 32.5, 255.0, 0.0, 36.5, 255.0, 0.0, 40.5, 255.0, 0.0, 44.5, 255.0, 0.0, 48.5, 255.0, 0.0, 52.5, 255.0, 0.0, 56.5, 255.0, 0.0, 60.5, 255.0, 0.0, 64.5, 255.0, 0.0, 68.5, 255.0, 0.0, 72.5, 255.0, 0.0, 76.5, 255.0, 0.0, 80.5, 255.0, 0.0, 84.5, 255.0, 0.0, 88.5, 255.0, 0.0, 92.5, 255.0, 0.0, 96.5, 255.0, 0.0, 100.5, 255.0, 0.0, 104.5, 255.0, 0.0, 108.5, 255.0, 0.0, 112.5, 255.0, 0.0, 116.5, 255.0, 0.0, 120.5, 255.0, 0.0, 124.5, 255.0, 0.0, 128.5, 255.0, 0.0, 132.5, 255.0, 0.0, 136.5, 255.0, 0.0, 140.5, 255.0, 0.0, 144.5, 255.0, 0.0, 148.5, 255.0, 0.0, 152.5, 255.0, 0.0, 156.5, 255.0, 0.0, 160.5, 255.0, 0.0, 164.5, 255.0, 0.0, 168.5, 255.0, 0.0, 172.5, 255.0, 0.0, 176.5, 255.0, 0.0, 180.5, 255.0, 0.0, 184.5, 255.0, 0.0, 188.5, 255.0, 0.0, 192.5, 255.0, 0.0, 196.5, 255.0, 0.0, 200.5, 255.0, 0.0, 204.5, 255.0, 0.0, 208.5, 255.0, 0.0, 212.5, 255.0, 0.0, 216.5, 255.0, 0.0, 220.5, 254.032258065, 0.0, 224.5, 250.806451613, 0.0, 228.5, 247.580645161, 2.41935483871, 232.5, 244.35483871, 5.64516129032, 236.5, 241.129032258, 8.87096774194, 240.5, 237.903225806, 12.0967741935, 244.5, 234.677419355, 15.3225806452, 248.5, 231.451612903, 18.5483870968, 252.5, 228.225806452, 21.7741935484, 255.0, 225.0, 25.0, 255.0, 221.774193548, 28.2258064516, 255.0, 218.548387097, 31.4516129032, 255.0, 215.322580645, 34.6774193548, 255.0, 212.096774194, 37.9032258065, 255.0, 208.870967742, 41.1290322581, 255.0, 205.64516129, 44.3548387097, 255.0, 202.419354839, 47.5806451613, 255.0, 199.193548387, 50.8064516129, 255.0, 195.967741935, 54.0322580645, 255.0, 192.741935484, 57.2580645161, 255.0, 189.516129032, 60.4838709677, 255.0, 186.290322581, 63.7096774194, 255.0, 183.064516129, 66.935483871, 255.0, 179.838709677, 70.1612903226, 255.0, 176.612903226, 73.3870967742, 255.0, 173.387096774, 76.6129032258, 255.0, 170.161290323, 79.8387096774, 255.0, 166.935483871, 83.064516129, 255.0, 163.709677419, 86.2903225806, 255.0, 160.483870968, 89.5161290323, 255.0, 157.258064516, 92.7419354839, 255.0, 154.032258065, 95.9677419355, 255.0, 150.806451613, 99.1935483871, 255.0, 147.580645161, 102.419354839, 255.0, 144.35483871, 105.64516129, 255.0, 141.129032258, 108.870967742, 255.0, 137.903225806, 112.096774194, 255.0, 134.677419355, 115.322580645, 255.0, 131.451612903, 118.548387097, 255.0, 128.225806452, 121.774193548, 255.0, 125.0, 125.0, 255.0, 121.774193548, 128.225806452, 255.0, 118.548387097, 131.451612903, 255.0, 115.322580645, 134.677419355, 255.0, 112.096774194, 137.903225806, 255.0, 108.870967742, 141.129032258, 255.0, 105.64516129, 144.35483871, 255.0, 102.419354839, 147.580645161, 255.0, 99.1935483871, 150.806451613, 255.0, 95.9677419355, 154.032258065, 255.0, 92.7419354839, 157.258064516, 255.0, 89.5161290323, 160.483870968, 255.0, 86.2903225806, 163.709677419, 255.0, 83.064516129, 166.935483871, 255.0, 79.8387096774, 170.161290323, 255.0, 76.6129032258, 173.387096774, 255.0, 73.3870967742, 176.612903226, 255.0, 70.1612903226, 179.838709677, 255.0, 66.935483871, 183.064516129, 255.0, 63.7096774194, 186.290322581, 255.0, 60.4838709677, 189.516129032, 255.0, 57.2580645161, 192.741935484, 255.0, 54.0322580645, 195.967741935, 255.0, 50.8064516129, 199.193548387, 255.0, 47.5806451613, 202.419354839, 255.0, 44.3548387097, 205.64516129, 255.0, 41.1290322581, 208.870967742, 255.0, 37.9032258065, 212.096774194, 255.0, 34.6774193548, 215.322580645, 255.0, 31.4516129032, 218.548387097, 255.0, 28.2258064516, 221.774193548, 255.0, 25.0, 225.0, 255.0, 21.7741935484, 228.225806452, 255.0, 18.5483870968, 231.451612903, 255.0, 15.3225806452, 234.677419355, 255.0, 12.0967741935, 237.903225806, 255.0, 8.87096774194, 241.129032258, 252.037037037, 5.64516129032, 244.35483871, 248.333333333, 2.41935483871, 247.580645161, 244.62962963, 0.0, 250.806451613, 240.925925926, 0.0, 254.032258065, 237.222222222, 0.0, 255.0, 233.518518519, 0.0, 255.0, 229.814814815, 0.0, 255.0, 226.111111111, 0.0, 255.0, 222.407407407, 0.0, 255.0, 218.703703704, 0.0, 255.0, 215.0, 0.0, 255.0, 211.296296296, 0.0, 255.0, 207.592592593, 0.0, 255.0, 203.888888889, 0.0, 255.0, 200.185185185, 0.0, 255.0, 196.481481481, 0.0, 255.0, 192.777777778, 0.0, 255.0, 189.074074074, 0.0, 255.0, 185.37037037, 0.0, 255.0, 181.666666667, 0.0, 255.0, 177.962962963, 0.0, 255.0, 174.259259259, 0.0, 255.0, 170.555555556, 0.0, 255.0, 166.851851852, 0.0, 255.0, 163.148148148, 0.0, 255.0, 159.444444444, 0.0, 255.0, 155.740740741, 0.0, 255.0, 152.037037037, 0.0, 255.0, 148.333333333, 0.0, 255.0, 144.62962963, 0.0, 255.0, 140.925925926, 0.0, 255.0, 137.222222222, 0.0, 255.0, 133.518518519, 0.0, 255.0, 129.814814815, 0.0, 255.0, 126.111111111, 0.0, 255.0, 122.407407407, 0.0, 255.0, 118.703703704, 0.0, 255.0, 115.0, 0.0, 255.0, 111.296296296, 0.0, 255.0, 107.592592593, 0.0, 255.0, 103.888888889, 0.0, 255.0, 100.185185185, 0.0, 255.0, 96.4814814815, 0.0, 255.0, 92.7777777778, 0.0, 255.0, 89.0740740741, 0.0, 255.0, 85.3703703704, 0.0, 255.0, 81.6666666667, 0.0, 255.0, 77.962962963, 0.0, 255.0, 74.2592592593, 0.0, 255.0, 70.5555555556, 0.0, 255.0, 66.8518518519, 0.0, 255.0, 63.1481481481, 0.0, 255.0, 59.4444444444, 0.0, 255.0, 55.7407407407, 0.0, 255.0, 52.037037037, 0.0, 255.0, 48.3333333333, 0.0, 255.0, 44.6296296296, 0.0, 255.0, 40.9259259259, 0.0, 255.0, 37.2222222222, 0.0, 255.0, 33.5185185185, 0.0, 255.0, 29.8148148148, 0.0, 255.0, 26.1111111111, 0.0, 255.0, 22.4074074074, 0.0, 254.772727273, 18.7037037037, 0.0, 250.227272727, 15.0, 0.0, 245.681818182, 11.2962962963, 0.0, 241.136363636, 7.59259259259, 0.0, 236.590909091, 3.88888888889, 0.0, 232.045454545, 0.185185185185, 0.0, 227.5, 0.0, 0.0, 222.954545455, 0.0, 0.0, 218.409090909, 0.0, 0.0, 213.863636364, 0.0, 0.0, 209.318181818, 0.0, 0.0, 204.772727273, 0.0, 0.0, 200.227272727, 0.0, 0.0, 195.681818182, 0.0, 0.0, 191.136363636, 0.0, 0.0, 186.590909091, 0.0, 0.0, 182.045454545, 0.0, 0.0, 177.5, 0.0, 0.0, 172.954545455, 0.0, 0.0, 168.409090909, 0.0, 0.0, 163.863636364, 0.0, 0.0, 159.318181818, 0.0, 0.0, 154.772727273, 0.0, 0.0, 150.227272727, 0.0, 0.0, 145.681818182, 0.0, 0.0, 141.136363636, 0.0, 0.0, 136.590909091, 0.0, 0.0, 132.045454545, 0.0, 0.0, 0.0, 0.0, 0.0], np.int)
